/******************************************************************************/
//	InputManager.h	-	provides input functionality for the keyboard & mouse
//
//	Author:		Russell Klinkerman
//	Created:	12.06.2004
/******************************************************************************/

#include "InputManager.h"
#include "AppCore.h"
#include <stdio.h>
#include "KlinkTimer.h"

CInputManager inputManager;

/***********/
/* GENERAL
/***********/

bool	CInputManager::Init()
{
	HRESULT hr = 0;
	hAppWnd = appCore.GetWnd();

	// Obtain the DirectInput Interface
	if(FAILED(hr = DirectInput8Create(appCore.GetInstance(), DIRECTINPUT_VERSION, 
			IID_IDirectInput8, (void**)&pInputInterface, NULL)))
	{
		MessageBox(NULL, "Failed to Created Input Interface", "!Error!", MB_OK);
	}

	// Create and setup keyboard
	pInputInterface->CreateDevice(GUID_SysKeyboard, &pKeyboardDevice, NULL);
	pKeyboardDevice->SetDataFormat(&c_dfDIKeyboard);
	pKeyboardDevice->SetCooperativeLevel(hAppWnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);

	// Set the device properties
	DIPROPDWORD	diKeyboardProperties;

	memset(&diKeyboardProperties, 0, sizeof(DIPROPDWORD));
    diKeyboardProperties.diph.dwSize       = sizeof(DIPROPDWORD);
    diKeyboardProperties.diph.dwHeaderSize = sizeof(DIPROPHEADER);
    diKeyboardProperties.diph.dwObj        = 0;
    diKeyboardProperties.diph.dwHow        = DIPH_DEVICE;
    diKeyboardProperties.dwData            = KEYBOARD_BUFFERED_SIZE;

	pKeyboardDevice->SetProperty(DIPROP_BUFFERSIZE, &diKeyboardProperties.diph);
	pKeyboardDevice->Acquire();

	// Create and setup mouse
	pInputInterface->CreateDevice(GUID_SysMouse, &pMouseDevice, NULL);
	pMouseDevice->SetDataFormat(&c_dfDIMouse2);
	pMouseDevice->SetCooperativeLevel(hAppWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
	pMouseDevice->Acquire();

	// Upon success...
	return true;
}

bool	CInputManager::Shutdown()
{
	// Unacquire & Release Mouse Device
	if(pMouseDevice)
	{
		pMouseDevice->Unacquire();
		pMouseDevice->Release();
	}

	// Unacquire & Release Keyboard Device
	if(pKeyboardDevice)
	{
		pKeyboardDevice->Unacquire();
		pKeyboardDevice->Release();
	}

	// Release Input Interface
	SAFE_RELEASE(pInputInterface);

	// Upon success...
	return true;
}

/************/
/* KEYBOARD
/************/

bool	CInputManager::ProcessKeyboard()
{
	HRESULT hr = 0;

	// Clear the immediate keyboard data
	memset(diImmediateKeyboardData, 0, sizeof(char) * KEYBOARD_IMMEDIATE_SIZE);

	// Fill the immediate keyboard data with fresh data
	if(FAILED(hr = pKeyboardDevice->GetDeviceState(KEYBOARD_IMMEDIATE_SIZE, diImmediateKeyboardData)))
	{
		if(hr == DIERR_INPUTLOST &&
			FAILED(hr = pKeyboardDevice->Acquire()))
				MessageBox(appCore.GetWnd(), "CInputManager::ProcessKeyboard() - Unable to re-acquire device", "Error", MB_OK);

		// Function failed...
		return false;
	}

	// Reset buffer size
	uiBufferedKeyboardSize	=	KEYBOARD_BUFFERED_SIZE;

	// Clear the buffered keyboard data
	memset(diBufferedKeyboardData, 0, sizeof(DIDEVICEOBJECTDATA) * KEYBOARD_BUFFERED_SIZE);

	// Fill the buffered keyboard data
	if(FAILED(hr == pKeyboardDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), diBufferedKeyboardData,
										(DWORD*)&uiBufferedKeyboardSize, 0)))
	{
		if(hr == DIERR_INPUTLOST &&
			FAILED(hr = pKeyboardDevice->Acquire()))
				MessageBox(appCore.GetWnd(), "CInputManager::ProcessKeyboard() - Unable to re-acquire device", "Error", MB_OK);

		// Function failed...
		return false;
	}

	// Upon success...
	return true;
}

bool	CInputManager::IsKeyDown(int _dxKeyCode)
{
	// Check the key.
	return (diImmediateKeyboardData[_dxKeyCode] & 0x80) ? true : false;
}

bool	CInputManager::IsKeyDownBuffered(int _dxKeyCode)
{
	// Cycle through the keyboard buffer
	for(unsigned int i = 0; i < uiBufferedKeyboardSize; i++)
	{
		// Check if the key was pressed.
		if(diBufferedKeyboardData[i].dwOfs == _dxKeyCode && (diBufferedKeyboardData[i].dwData & 0x80))
				return true;
	}

	// If not...
	return false;
}


/*********/
/* MOUSE
/*********/

bool	CInputManager::ProcessMouse()
{
	HRESULT hr = 0;

	// Clear the immediate mouse state
	memset(&diMouseState, 0, sizeof(diMouseState));

	// Fill the immediate mouse state with fresh data
	if(FAILED(hr = pMouseDevice->GetDeviceState(sizeof(diMouseState), (void*)&diMouseState)))
	{
		if(hr == DIERR_INPUTLOST && 
			FAILED(hr = pMouseDevice->Acquire()))
				MessageBox(appCore.GetWnd(), "CInputManager::ProcessMouse() - Unable to re-acquire device", "Error", MB_OK);

		// Function failed...
		return false;
	}

	// Upon success...
	return true;
}

bool	CInputManager::IsMouseDown(int nMouseButton)
{
	return (diMouseState.rgbButtons[nMouseButton] & 0x80) ? true : false ;
}

void	CInputManager::GetMouseDelta(int &_nDeltaX, int &_nDeltaY, int &_nDeltaZ)
{
	_nDeltaX = diMouseState.lX;	//	Set the delta change in mouse position
	_nDeltaY = diMouseState.lY;
	_nDeltaZ = diMouseState.lZ;
}